package com.magenta.maxoptra.gis.commons;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
import java.util.TimeZone;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * User: ivictus
 * Date: 04.08.2010
 * Time: 18:50:36
 * Project: maxoptra-1.3
 */
public class MsgTranslator implements Translator {

    public static interface DatePlugin {
        Pattern getDateTag();

        int getDateTagMaxLength();

        String convertDateTime(String in, TimeZone tz, DateFormat fmt);
    }

    private final Map<String, String> dictionary;
    private DateFormat fmt;
    private TimeZone tz;
    private DatePlugin dp;

    public MsgTranslator(Map<String, String> dictionary, DatePlugin plugin) {
        this.dictionary = dictionary;
        fmt = new SimpleDateFormat();
        tz = TimeZone.getDefault();
        //SETUP USER DEFINED VALUES
        //for (Plugin plugin : plugins) {
        //    if (plugin instanceof DatePlugin) {
        //        dp = (DatePlugin) plugin;
        //    }
        //}
        this.dp = plugin;
        //SETUP DEFAULT VALUES
        if (dp == null) {
            dp = new DateAsLong();
        }
    }

    @Override
    public String translate(String template) {
        //NOTHING DO IF NULL
        if (template == null) {
            return "";
        }
        //Window technique
        int windowLength = Math.max(getMaxWordLength(dictionary), dp.getDateTagMaxLength());
        int startPos = 0;
        StringBuilder output = new StringBuilder(template.length());
        while (startPos + windowLength <= template.length()) {
            String window = template.substring(startPos, startPos + windowLength);
            int translated = applyDict(window, dictionary, tz, fmt, output);
            if (translated == 0) {
                translated++; // начать поиск со следующего символа
            }
            startPos += translated;
        }
        if (startPos + windowLength > template.length()) {
            String window = template.substring(startPos, template.length());
            applyDict(window, dictionary, tz, fmt, output);
        }
        return output.toString();
    }

    private int applyDict(String sentence, Map<String, String> dict, TimeZone tz, DateFormat fmt, StringBuilder output) {
        int translated = 0;
        //WITHOUT INCLUDED BRACKETS
        boolean inKey = false;
        int startPos = -1;
        int endPos = -1;
        for (int i = 0; i < sentence.length(); i++) {
            char ch = sentence.charAt(i);
            if (ch == '<') {
                inKey = true;
                startPos = i;
            }
            if (!inKey) {
                output.append(ch);
                translated++;
            }
            if (ch == '>' && inKey) {
                endPos = i;
                inKey = false;
            }
            if (startPos > -1 && endPos > -1) {
                String key = sentence.substring(startPos, endPos + 1);
                String val = dict.get(key);
                if (val != null) {
                    output.append(val);
                } else {
                    Matcher timeMatcher = dp.getDateTag().matcher(key);
                    if (timeMatcher.matches()) {
                        String time = key.substring(1 + 4, key.length() - 1);
                        String userTime = dp.convertDateTime(time, tz, fmt);
                        output.append(userTime);
                    } else {
                        output.append(key);
                    }
                }
                //translated is a count, but position is a index
                translated = endPos + 1;
                startPos = -1;
                endPos = -1;
            }
        }
        //FIRST SYMBOL '<'
        if (inKey && startPos == 0) {
            output.append(sentence);
            translated = sentence.length();
        }
        return translated;
    }

    private static int getMaxWordLength(Map<String, String> dictionary) {
        int maxKeyLength = 0;
        for (String key : dictionary.keySet()) {
            if (key.length() > maxKeyLength) {
                maxKeyLength = key.length();
            }
        }
        return maxKeyLength;
    }


    @Override
    public void setDateFormat(String fmt) {
        this.fmt = new SimpleDateFormat(fmt);
    }

    @Override
    public void setTimeZone(TimeZone tz) {
        this.tz = tz;
    }

    private class DateAsLong implements DatePlugin {
        public final Pattern DATE_TAG = Pattern.compile(".*<date[^>]+>.*");

        private final static int DATE_TAG_MAX_LENGTH = 19 + 4 + 2; //2 on brackets

        @Override
        public Pattern getDateTag() {
            return DATE_TAG;
        }

        @Override
        public int getDateTagMaxLength() {
            return DATE_TAG_MAX_LENGTH;
        }

        @Override
        public String convertDateTime(String in, TimeZone tz, DateFormat fmt) {
            long time = toLong(in);
            fmt.setTimeZone(tz);
            return fmt.format(new Date(time));
        }

        private long toLong(String str) {
            long value = 0;
            for (char ch : str.toCharArray()) {
                value = 10 * value + (ch - 48);
            }
            return value;
        }
    }
}
